#define GL_GLEXT_PROTOTYPES

#include "openglframe.h"
#include <algorithm>

#include "../glDrawFunctions.h"

// Some utility Functions ===================================================================

/// Returns the screen coordinates of a point in world space.
/// @param p input point in screen space
/// @return point in world space
Point worldToScreen (Point p) 
{
    int viewport[4];
    double mvmatrix[16], projmatrix[16], wincoord[3];
    glGetIntegerv (GL_VIEWPORT, viewport);
    glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
    glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
    gluProject (p.x(), p.y(), p.z(),
               mvmatrix, projmatrix, viewport,
               &wincoord[0], &wincoord[1], &wincoord[2]);
    return Point (wincoord[0], wincoord[1], wincoord[2]);
}

/// Returns the world coordinates of a point in screen space.
/// @param p input point in world space
/// @return point in screen space
Point screenToWorld (Point p) 
{
    int viewport[4];
    double mvmatrix[16], projmatrix[16], wldcoord[3];
    glGetIntegerv (GL_VIEWPORT, viewport);
    glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
    glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
    gluUnProject (p.x(), p.y(), p.z(),
            mvmatrix, projmatrix, viewport,
            &wldcoord[0], &wldcoord[1], &wldcoord[2]);
    return Point (wldcoord[0], wldcoord[1], wldcoord[2]);
}

// OpenGLFrame methods ====================================================================

/// Constructor.
/// @param parent widget.
/// @param shareWidget widget sharing the same opengl context.
/// @param f Qt window flags.
OpenGLFrame::OpenGLFrame(QWidget* parent, const QGLWidget* shareWidget, Qt::WFlags f)
   : QGLWidget (parent, shareWidget, f), objects(), sceneTransform(), arcball(1,1) {
   
   // for keyboard use 
   setFocusPolicy(Qt::StrongFocus);
   
   sceneTransform = Transformation(CGAL::IDENTITY);
   //~ addKeyPoint(); // add a default keypoint
   currentKey = 0;
   poseInterpolator = 0;
   deformableMesh = 0;
   cursor3D = Point(0,0,0);
   interactionMode = SELECT_MODE;
   
   deformer = 0;
   currentmodel = 0;
   
   fovy = 40.0;
   zoomFactor = 1.0;
   meshrendermode_mask = 0x20;
   
   texFloor = 0;
   poseid = 0;
   id_picgrab = 0;
   was_ckeypointselected = false;
   is_shadowdragging = false;
   
   is_pic_capturing = false;
   is_mesh_capturing = false;
   
   interKeyPoints.reserve(100000);
   isProjOrtho = true; // orthographic projection
   is_lightingOn = true;
   
   njoints = 0;
   
   viewitems_mask = 0x0; 
   viewitems_mask = viewitems_mask | MODELDEF;
   viewitems_mask = viewitems_mask | SKELETONDEF;
   viewitems_mask = viewitems_mask | KEYPOINTS;
   viewitems_mask = viewitems_mask | CONSTRAINTS;
   viewitems_mask = viewitems_mask | FLOOR;
   viewitems_mask = viewitems_mask | INFO;
   viewitems_mask = viewitems_mask | CURRENTKEYPOINT;
   viewitems_mask = viewitems_mask | SHADOW;
   
   rotationCompTech = AXISANGLE;
   
   //~ keyPointCurrent = 0;
   Vector displacement = cursor3D - Point(0,0,0);
   //~ keyPointCurrent = new DrawableInstance(&dot, Transformation(CGAL::TRANSLATION, displacement));
   keyPointCurrent = new DrawableInstance(&sphere, Transformation(CGAL::TRANSLATION, displacement));
   
   // Floor and shadow specificacion
   floor[0] = Point(-4.5,0.0, 4.5);
   floor[1] = Point( 4.5,0.0, 4.5);
   floor[2] = Point( 4.5,0.0,-4.5);
   floor[3] = Point(-4.5,0.0,-4.5);
   pfloor = Plane(floor[0], floor[2], floor[1]);
   
   float l[] = {0.0, 50.0, 0.0}; // Coordinates of the light source
   float e[] = {0.0, 0.0, 0.0};  // Point of the floor plane
   float n[] = {0.0, -1.0, 0.0}; // Normal vector for the plane
   createShadowProjectionMatrix(l,e,n);
}

OpenGLFrame::~OpenGLFrame() {
   
   if (deformer!=0)           delete deformer;
   if (currentmodel!=0)       delete currentmodel;
}

/// Sets the interaction mode
void OpenGLFrame::setInteractionMode (InteractionMode m) 
{
   interactionMode = m;
}

void OpenGLFrame::buildModelClones(unsigned int n) {
   
   if (currentmodel == 0) return;
   
   models.clear();    trans.clear();
   models.reserve(n); trans.reserve(n);
   
   // insert the current model
   models.push_back(currentmodel);
   trans.push_back(Vector(0.0,0.0,0.0));
   
   unsigned int limx=4; float x=0.0, z=0.0;
   for (unsigned int c=0, i=0; c<n; ++c, ++i) {
      if (i<limx)   x+=0.5; 
      else        { z+=0.5; x=0.5; i=0; }
      models.push_back(currentmodel);
      trans.push_back(Vector(x,0.0,z));
   }
}

bool OpenGLFrame::loadShape(const QString& filename) {
   
   QFileInfo fi(filename);
   QString extension = fi.suffix();
   MeshWithSkeleton *newmodel = 0;
   //~ newmodel = MeshWithSkeleton::load_off(filename.toStdString().c_str());
   
   if (extension == "off")
      newmodel = MeshWithSkeleton::load_off(filename.toStdString().c_str());
   else if (extension == "ply")
      newmodel = MeshWithSkeleton::load_ply(filename.toStdString().c_str());
   else 
      return false;
   
   if (newmodel) {
      if (currentmodel!=0) delete currentmodel;
      currentmodel = newmodel;
      
      models.push_back(currentmodel);
      trans.push_back(Vector(0,0,0));
      
      genWorldLimits();
      setGLview();
      
      cout<<"loadShapeOFF ... end"<<endl;
      
      return true;
   }
   return false;
}

bool OpenGLFrame::saveShapeOFF(const QString& filename) {
   
   if (currentmodel) { 
      currentmodel->saveShapeOFF(filename.toStdString().c_str());
      return true;
   }
   return false;
}

bool OpenGLFrame::load_skeleton(const QString& filename) {
   
   if (currentmodel == 0) return false;
   currentmodel->loadSkeleton(filename.toStdString().c_str());
   if (currentmodel->skeleton != 0) njoints = currentmodel->skeleton->nJoints();
   return true;
}

bool OpenGLFrame::loadSkinning(const QString& filename) {
   
   if (currentmodel==0) return false;
   if (filename.contains(".sj"))
      currentmodel->loadSkinningOnJoints(filename.toStdString().c_str());
   else if (filename.contains(".sb"))
      currentmodel->loadSkinningOnBones(filename.toStdString().c_str());
   return true;
}

bool OpenGLFrame::load_poses(const QString& filename) {
   
   if (filename == "") return false;
   // Load the poses 
   ifstream posesfile(filename.toStdString().c_str());
   if (not posesfile.is_open()) {
      std::cout<<"I/O error: grrr the file doesn't exist "<<std::endl;
      return false;
   }
   
   string posesformat;
   int nposes, nconstraints;
   // Load header
   posesfile>>posesformat;
   assert(posesformat=="POSES_SKEL" or posesformat=="POSES_MESH");
   posesfile>>nposes>>nconstraints;
   
   cout<<posesformat<<" "<<nposes<<" "<<nconstraints<<endl;
   
   // Load the constraint identifiers
   vector<int> cnstr(nconstraints); // constra
   for (int i=0; i<nconstraints; ++i) {
      posesfile>>cnstr[i];
   }
   
   // Load the ctrl point positions
   for (int i=0; i<cnstr.size(); ++i) {
      int id = cnstr[i];
      Point3 p;
      if (posesformat=="POSES_SKEL") 
         p = currentmodel->skeleton->getJointPosition(id);
      else if (posesformat=="POSES_MESH") 
         p = currentmodel->getVertexPosition(id);
      else 
         assert(false);
      
      cursor3D = Point (p[0], p[1], p[2]);
      addRestriction();
      
      Point3 po(p[0], p[1], p[2]);
      constraints.push_back(po, id);
   }
   
   // Reserve memory
   poses.reserve(nposes);
   // Load the data
   Number x, y, z;
   for (unsigned int i=0; i<nposes; ++i) {
      vector<Vector> pose;
      for (unsigned int j=0; j<nconstraints; ++j) {
         posesfile>>x>>y>>z;
         pose.push_back(Vector(x,y,z));
      }
      poses.push_back(pose);
   }
   
   poseid = 0;
   
   return true;
}

void OpenGLFrame::saveAsPoses(const QString& filename) {
   
   if (filename == "") return;
   // Load the poses 
   ofstream posesfile(filename.toStdString().c_str());
   if (not posesfile.is_open()) {
      std::cout<<"grrrr there is a I/O error"<<std::endl;
      return;
   }
   
   cout<<"poses.empty(): "<<poses.empty()<<endl;
   cout<<"constraints.empty(): "<<constraints.empty()<<endl;
   
   if(poses.empty()) { std::cout<<"there isnot poses data"<<std::endl; return;}
   if(constraints.empty()) { std::cout<<"there isnot constraints data"<<std::endl; return;}
   
   // Save the header
   string posesformat;
   if (currentmodel->skeleton == 0)
      posesformat = "POSES_MESH";
   else 
      posesformat = "POSES_SKEL";
   posesfile<<posesformat<<endl;
   posesfile<<poses.size()<<" "<<constraints.size()<<endl;
   
   // Save the constraint identifiers
   for (int i=0; i<constraints.size(); ++i) {
      posesfile<<constraints.ids[i]<<" ";
   }
   posesfile<<endl;
   
   // Save the poses data
   Number x, y, z;
   for (unsigned int i=0; i<poses.size(); ++i) {
      const vector<Vector> &pose = poses[i];
      for (unsigned int j=0; j<pose.size(); ++j) {
         const Vector &v = pose[j];
         posesfile<<v[0]<<" "<<v[1]<<" "<<v[2]<<" ";
      }
      posesfile<<endl;
   }
   
   posesfile.close();
}

/// Adds a new object to the scene.
/// @param obj pointer to a drawable whose instance will be added to the scene.
void OpenGLFrame::addObject(Drawable* obj, bool deformable) {
   
   Vector displacement = cursor3D - Point(0,0,0);
   DrawableInstance* instance = 
      new DrawableInstance (obj, Transformation(CGAL::TRANSLATION, displacement));
   objects.push_back (instance);
   if (deformable) {
      deformableMesh = instance;
      // Just a hack to make the restriction spheres appear suitably smaller than
      // the currentmodel
      sphere = Sphere (obj->box.diameter()/150.0);
   }
}

void checkingGLerrors(const char *label) {
   
   GLenum errCode;
   const GLubyte *errStr;
   if ((errCode = glGetError()) != GL_NO_ERROR) {
      errStr = gluErrorString(errCode);
      printf("OpenGL ERROR: ");
      printf((char*)errStr);
      printf("(Label: ");
      printf(label);
      printf(")\n.");
   }
}

/// Adds a new keyPoint to the scene.
void OpenGLFrame::addKeyPoint () {
   
   if (objects.empty()) { 
      cout<<" ... # The initial pose is not defined"<<endl;
      return;
   }
   
   keyPoints.push_back(new DrawableInstance(&sphere, keyPointCurrent->getTransformation()));
   storeStance(keyPoints.size()-1);
   
   cout<<"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"<<endl;
   if (deformer==0) {
      checkingGLerrors("addKeyPoint()");
      if (currentmodel->skeleton == 0)
         deformer = new DeformationMesh(currentmodel);
      else
         deformer = new DeformationSkelMesh(currentmodel);
      //~ deformer = new DeformationShape_VSGPU;
      //~ deformer = new DeformationShape_FSGPU;
      //~ deformer = new DeformationShape_FSGPU_L1;
      deformer->setting(&constraints);
      deformer->setRotationCompTech(rotationCompTech);
   }
   cout<<"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"<<endl;
   
   //~ currentKey = keyPoints
   //~ currentKey = isel-objects.size();
   //~ retrieveStance(currentKey);
}

/// Adds a new Restriction to the scene.
void OpenGLFrame::addRestriction () {
   
   // Draw Restrictions as a sphere
   Vector displacement = cursor3D - Point(0,0,0);
   objects.push_back (new DrawableInstance (&sphere, Transformation(CGAL::TRANSLATION, displacement)));
}

/// OpenGL initialization.
void OpenGLFrame::initializeGL() {
   
   glClearColor(1,1,1,0);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_NORMALIZE);
   glShadeModel(GL_SMOOTH);
   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
   
   // lighting setup
   GLfloat left_light_position[] =  {0.0, 2.0, 2.0, 0.0};
   GLfloat right_light_position[] = {0.0, -2.0, 2.0, 0.0};
   glLightfv(GL_LIGHT0, GL_POSITION, left_light_position);
   glLightfv(GL_LIGHT1, GL_POSITION, right_light_position);
   GLfloat left_diffuse_light[] =  {1.0f, 1.0f, 1.0f, 1.0f};
   GLfloat right_diffuse_light[] = {1.0f, 1.0f, 1.0f, 1.0f};
   glLightfv(GL_LIGHT0, GL_DIFFUSE, left_diffuse_light);
   glLightfv(GL_LIGHT1, GL_DIFFUSE, right_diffuse_light);
   
   checkingGLerrors("initializeGL() 111111111");
//   loadKeyPointSpriteTexture();
   checkingGLerrors("initializeGL() 2222222222222");
   genWorldLimits();
   
   checkingGLerrors("initializeGL() 333333333");
   texFloor = new Texture("icons/floor5.png", GL_TEXTURE_2D);
   assert(texFloor != 0);
   
   checkingGLerrors("initializeGL() 44444444444");
   
   //~ setGLview();
}

/// A simple opengl drawing callback.
void OpenGLFrame::paintGL() {
   
   checkingGLerrors("000000");
   
   setGLview();
   
   checkingGLerrors("111111111");
   
   glClearStencil(0x1);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   
   checkingGLerrors("2222222");
   
   glTransform(sceneTransform);
   
   checkingGLerrors("3333333333");
   
   // Draw the floor
   if ((viewitems_mask & FLOOR) == FLOOR)
      drawFloor();
   
   // Render Shadows
   if ((viewitems_mask & SHADOW) == SHADOW) {
      glDisable(GL_LIGHTING);
      glPushMatrix();
      //~ float l[] = {15.0, 50.0, 30.0}; // Coordinates of the light source
      //~ float l[] = {0.0, 50.0, 0.0}; // Coordinates of the light source
      //~ float e[] = {0.0, -0.5, 0.0}; // Point of the plane
      //~ float n[] = {0.0, -1.0, 0.0}; // Normal vector for the plane
      //~ glShadowProjection(l,e,n);
      //~ glDrawModel(currentmodel, FLAT);
      glMultMatrixf(shadowMatrix);
      glColor4f(0.0f, 0.0f, 0.0f, 1.0);
      glDrawModel(currentmodel, FLAT);
      glColor4f(0.0f, 0.0f, 0.3f, 1.0);
      if ((viewitems_mask & CONSTRAINTS) == CONSTRAINTS) 
         drawObjectsConstraints();
      glColor4f(0.3f, 0.0f, 0.0f, 1.0);
      if ((viewitems_mask & KEYPOINTS) == KEYPOINTS)
         drawKeyPoints();
      glColor4f(0.0f, 0.3f, 0.0f, 1.0);
      if ((viewitems_mask & CURRENTKEYPOINT) == CURRENTKEYPOINT)
         drawCurrentKeyPoint();
      glPopMatrix();
      glEnable(GL_LIGHTING);
   }
   
   checkingGLerrors("444444444");
   
    // Draw the currentmodel
   if ((viewitems_mask & MODELDEF) == MODELDEF) {
      //~ if (deformer != 0) deformer->use(true);
      
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_NORMAL_ARRAY);
      //~ glEnableClientState(GL_COLOR_ARRAY);
      
      typedef Mesh::Vertex Vertex;
      Vertex_iterator vi = currentmodel->vertices_begin();
      glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &(vi->point()[0]));
      glNormalPointer(GL_FLOAT, sizeof(Vertex), &(vi->normal()[0]));
      //~ glColorPointer(3, GL_FLOAT, 0, &currentmodel->colors[0]);
      
      static GLfloat colrf[4] = {0.0f, 0.5f, 1.0f, 1.0f };
      static GLfloat colrb[4] = {1.0f, 0.0f, 0.0f, 1.0f };
      glMaterialfv(GL_FRONT, GL_DIFFUSE, colrf);
      glMaterialfv(GL_BACK, GL_DIFFUSE, colrb);
      
      glLineWidth(1.0);
      (is_lightingOn)? glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); 
      //~ glDrawModel(currentmodel, meshrendermode_mask);
      for (int i=0; i<models.size(); ++i) {
         glPushMatrix();
         glTranslatef(trans[i][0],trans[i][1],trans[i][2]);
         glDrawModel(models[i], meshrendermode_mask);
         glPopMatrix();
      }
      
      //~ glDisableClientState(GL_VERTEX_ARRAY);
      //~ glDisableClientState(GL_NORMAL_ARRAY);
      
      //~ if (deformer != 0) deformer->use(false);
   }
   
   checkingGLerrors("5555555");
   
   // Draw the skeleton
   if ((viewitems_mask & SKELETONDEF) == SKELETONDEF) {
      glDisable(GL_DEPTH_TEST);
      glDrawSkel(currentmodel->skeleton);
      glEnable(GL_DEPTH_TEST);
   }
   
   checkingGLerrors("66666666");
   
   // Draw the objects constraints
   if ((viewitems_mask & CONSTRAINTS) == CONSTRAINTS) {
      drawObjectsConstraints();
   }
   
   checkingGLerrors("777777");
   
   // Draw the keypoints
   if ((viewitems_mask & KEYPOINTS) == KEYPOINTS) {
      drawKeyPoints();
   }
   
   checkingGLerrors("888888888");
   
   // Draw the current keypoint
   if ((viewitems_mask & CURRENTKEYPOINT) == CURRENTKEYPOINT) 
      drawCurrentKeyPoint();
   
   /*
   glDrawPosesPaths(poses, i_constraints);
   glColor4f(0.0f, 0.0f, 0.5f, 1.0);
   glPointSize(10.0);
   glDrawPositions(constraints);
   
   if (deformer != 0) {
      glColor4f(0.0f, 0.5f, 0.5f, 1.0);
      glPointSize(4.0);
      glDrawCentroids(deformer->pstarList);
      glColor4f(0.5f, 0.5f, 0.0f, 1.0);
      glPointSize(4.0);
      glDrawCentroids(deformer->qstarList);
   }
   */
   
   // Draw the 3D cursor
   checkingGLerrors("999999999");
   
   // Render info
   if ((viewitems_mask & INFO) == INFO)
      renderInfo();
   
   checkingGLerrors("1000000000 dez");
   //~ cout<<"!!!!!!!!!!"<<endl;
   
}

void OpenGLFrame::renderInfo() {
   
   glDisable(GL_LIGHTING);
   glDisable(GL_DEPTH_TEST);
   
   frame++;
   std::time(&end);
   double ddifftime = std::difftime(end, start);
   if (ddifftime > 1) {
      cfps = frame/ddifftime;
      start = end;
      frame = 0;
   }
   
   //~ updateFps(time.elapsed());
   QString strInfoNv=QString("vertices: %1").arg(currentmodel->nvertices());
   QString strInfoNf=QString("faces: %1").arg(currentmodel->nfaces());
   QString strInfoNj=QString("joints: %1").arg(njoints);
   QString strInfoNcp=QString("control points: %1").arg(objects.size());
   QString strInfoNkp=QString("key poses: %1").arg(keyPoints.size());
   QString strPoseId=QString("poseid: %1").arg(poseid);
   QString strInfoFPS=QString("FPS: %1").arg(cfps,7,'f',1);
   
   glColor4f(0.0, 0.0, 0.0, 1.0);
   renderText(30,15, strInfoNv);
   renderText(30,30, strInfoNf);
   renderText(30,45, strInfoNj);
   renderText(30,60, strInfoNcp);
   renderText(30,75, strInfoNkp);
   renderText(30,90, strPoseId);
   renderText(30,105, strInfoFPS);
   
   glEnable(GL_LIGHTING);
   glEnable(GL_DEPTH_TEST);
}

void OpenGLFrame::drawObjectsConstraints() {
   
   // Prepare for drawing halo around selected objects
   //~ glPushAttrib(GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT);
   glStencilFunc(GL_ALWAYS, 0x0, 0x1);
   glStencilMask(0x1);
   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
   sort(selected.begin(), selected.end());
   
   glDisable(GL_DEPTH_TEST);
   // Draw every object
   // Draw the constraints
   unsigned isel = 0; 
   //~ if ((viewitems_mask & CONSTRAINTS) == CONSTRAINTS) {
      //~ glDisable(GL_DEPTH_TEST);
      glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 1); // used for lighting of quadric objects
      for (unsigned i = 0; i < objects.size(); i++) {
         glPushName(i);
         if (objects[i]->obj == &sphere) {
            // A restriction
            //~ static GLfloat colrfront[4] = {0.0f, 0.2f, 0.4f, 1.0f };
            static GLfloat colrfront[4] = {0.0f, 0.0f, 1.0f, 1.0f };
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, colrfront);
         } else {
            // A mesh
            glColor4f (0.5,0.0,0.0,1.0); 
         }
         if (isel < selected.size() && selected [isel] == (int) i) {
            // this is a selected object
            isel++;
            glEnable (GL_STENCIL_TEST);
            glPushMatrix();
            glTransform (group.getTransformation());
            objects[i]->draw();
            glPopMatrix();
            glDisable (GL_STENCIL_TEST);
         }
         else {
            objects[i]->draw();
         }
         glPopName();
      }
      glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); // used for lighting the quadric objects
      //~ glEnable(GL_DEPTH_TEST);
   //~ }
   //~ glPopAttrib();
   glEnable(GL_DEPTH_TEST);
      
   // Draw a halo around selected objects
   glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_LINE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
   glEnable(GL_STENCIL_TEST);
   glDisable(GL_DEPTH_TEST);
   glDisable(GL_LIGHTING);
   glStencilFunc(GL_EQUAL, 0x1, 0x1);
   glStencilMask(0x1);
   glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
   glLineWidth(5.0);
   glColor4f(1.0,1.0,0.0,1.0);
   glPushMatrix();
   glTransform (group.getTransformation());
   for (int isel = 0; isel < selected.size(); isel++) {
      int i = selected [isel];
      objects[i]->draw();
   }
   glPopMatrix();
   glPopAttrib();
   
}

void OpenGLFrame::drawObjectsConstraints_Select() {
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   glTransform(sceneTransform);
   
   sort(selected.begin(), selected.end());
   
   // Draw every object
   // Draw the constraints
   unsigned isel = 0; 
   if ((viewitems_mask & CONSTRAINTS) == CONSTRAINTS) {
      glDisable(GL_DEPTH_TEST);
      for (unsigned i = 0; i < objects.size(); i++) {
         glPushName(i);
         if (isel < selected.size() && selected [isel] == (int) i) {
            // this is a selected object
            isel++;
            glPushMatrix();
            glTransform (group.getTransformation());
            objects[i]->draw();
            glPopMatrix();
         }
         else {
            objects[i]->draw();
         }
         glPopName();
      }
      glEnable(GL_DEPTH_TEST);
   }
}

void OpenGLFrame::drawKeyPoints() {
   
    // Draw keyPoints
    glDisable(GL_DEPTH_TEST);
    GLfloat colrf[4] = {1.0f, 0.0f, 0.0f, 1.0f};
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, colrf);
    glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 1); // used for lighting of quadric objects
    
    for (unsigned i = 0; i < keyPoints.size(); i++) {
      // Distinguish keypoints from regular objects for the picking procedure
      // by adding the size of the objects array.
      glPushName(i);
      //~ glColor4f(1,0,0,1);
      glPushMatrix ();
      if (group.size() > 0 && group.group[0] == keyPoints[i]) {
         glTransform(group.getTransformation());
      }
      keyPoints[i]->draw();
      glPopMatrix();
      glPopName();
   }
   
   glEnable(GL_DEPTH_TEST);
   glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 0); // used for lighting of quadric objects
}

void OpenGLFrame::drawKeyPoints_Select() {
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   glTransform(sceneTransform);
   
   // Draw keyPoints
   glDisable(GL_LIGHTING);
   glDisable(GL_DEPTH_TEST);
   
   //~ glEnable(GL_POINT_SPRITE);
   glPointSize(30);
   for (unsigned i = 0; i < keyPoints.size(); i++) {
      // Distinguish keypoints from regular objects for the picking procedure
      // by adding the size of the objects array.
      glPushName(i);
      glColor4f(1,1,1,1);
      glPushMatrix ();
      if (group.size() > 0 && group.group[0] == keyPoints[i]) {
         glTransform(group.getTransformation());
      }
      keyPoints[i]->draw();
      glPopMatrix();
      glPopName();
   }
   
   glEnable(GL_DEPTH_TEST);
   glDisable(GL_LIGHTING);
}

void OpenGLFrame::drawCurrentKeyPoint() {
   
   glDisable(GL_DEPTH_TEST);
   GLfloat colrf[4] = {0.0f, 1.0f, 0.0f, 1.0f};
   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, colrf);
   glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 1); // used for lighting of quadric objects
   
   //~ glColor4f(0.3,0.3,0.3,1.0); // the shadow color
   int idkp = 1 + keyPoints.size(); // index of "current" key point
   glPushName(idkp);
   glPushMatrix();
   if (group.size() > 0 and group.group[0] == keyPointCurrent) 
      glTransform(group.getTransformation());
   keyPointCurrent->draw();
   glPopMatrix();
   glPopName();
   
   glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 0); // used for lighting of quadric objects
   glEnable(GL_DEPTH_TEST);
}

void OpenGLFrame::drawCurrentKeyPoint_Select() {
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   glTransform(sceneTransform);
   
   glDisable(GL_DEPTH_TEST);
   glPointSize(40);
   
   int idkp = 1 + keyPoints.size(); // index of "current" key point
   glPushName(idkp);
   glPushMatrix();
   if (group.size() > 0 and group.group[0] == keyPointCurrent) 
      glTransform(group.getTransformation());
   keyPointCurrent->draw();
   glPopMatrix();
   glPopName();
   
   glEnable(GL_DEPTH_TEST);
}

void OpenGLFrame::drawShadowCurrentKeyPoint_Select() {
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   glTransform(sceneTransform);
   
   // Render Shadows
   if ((viewitems_mask & SHADOW) == SHADOW) {
      glDisable(GL_LIGHTING);
      glColor4f(0.0f, 0.0f, 0.0f, 0.8);
      glPushMatrix();
      //~ float l[] = {15.0, 50.0, 30.0}; // Coordinates of the light source
      //~ float l[] = {0.0, 50.0, 0.0}; // Coordinates of the light source
      //~ float n[] = {0.0, -1.0, 0.0}; // Normal vector for the plane
      //~ float e[] = {0.0, -0.5, 0.0}; // Point of the plane
      //~ glShadowProjection(l,e,n);
      glMultMatrixf(shadowMatrix);
      //~ glDrawModel(currentmodel, FLAT);
      if ((viewitems_mask & CURRENTKEYPOINT) == CURRENTKEYPOINT) 
         drawCurrentKeyPoint();
      //~ drawObjectsConstraints();
      //~ keyPointCurrent->draw();
      glPopMatrix();
      glEnable(GL_LIGHTING);
   }
   
   //~ glEnable(GL_DEPTH_TEST);
}

void OpenGLFrame::drawShadowObjectsConstraints_Select() {
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(cameye[0],cameye[1],cameye[2],camcenter[0],camcenter[1],camcenter[2],0,1,0);
   glTransform(sceneTransform);
   
   // Render Shadows
   if ((viewitems_mask & SHADOW) == SHADOW) {
      glDisable(GL_LIGHTING);
      glColor4f(0.0f, 0.0f, 0.0f, 0.8);
      glPushMatrix();
      //~ float l[] = {15.0, 50.0, 30.0}; // Coordinates of the light source
      //~ float l[] = {0.0, 50.0, 0.0}; // Coordinates of the light source
      //~ float n[] = {0.0, -1.0, 0.0}; // Normal vector for the plane
      //~ float e[] = {0.0, -0.5, 0.0}; // Point of the plane
      //~ glShadowProjection(l,e,n);
      glMultMatrixf(shadowMatrix);
      //~ glDrawModel(currentmodel, FLAT);
      if ((viewitems_mask & CONSTRAINTS) == CONSTRAINTS) 
         drawObjectsConstraints();
      glPopMatrix();
      glEnable(GL_LIGHTING);
   }
   
   //~ glEnable(GL_DEPTH_TEST);
}

void OpenGLFrame::drawFloor() {
   
   glEnable(GL_TEXTURE_2D);
   texFloor->bind();
   
   static GLfloat colrf[4] = {1.0f, 1.0f, 1.0f, 1.0f };
   glMaterialfv(GL_FRONT, GL_DIFFUSE, colrf);

   glDisable(GL_LIGHTING);
   //~ glEnable(GL_LIGHTING);
   glPolygonMode(GL_FRONT, GL_FILL);
   glPolygonMode(GL_BACK, GL_LINE);
   //~ glEnable(GL_POLYGON_OFFSET_FILL);
   //~ glPolygonOffset(1,1);
   glColor3f(1.0,1.0,1.0);
   glBegin(GL_QUADS);
   glNormal3f(0.0,1.0,0.0);
   glTexCoord2d(0.0,0.0); glVertex3f(floor[0][0],floor[0][1], floor[0][2]);
   glTexCoord2d(1.0,0.0); glVertex3f(floor[1][0],floor[1][1], floor[1][2]);
   glTexCoord2d(1.0,1.0); glVertex3f(floor[2][0],floor[2][1], floor[2][2]);
   glTexCoord2d(0.0,1.0); glVertex3f(floor[3][0],floor[3][1], floor[3][2]);
   glEnd();
   glEnable(GL_LIGHTING);
   //~ glDisable(GL_LIGHTING);
   //~ glDisable(GL_POLYGON_OFFSET_FILL);
   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
   glColor4f(0.0f, 0.5f, 1.0f, 1.0f);
   
   glDisable(GL_TEXTURE_2D);
}

// This function is from http://www.devmaster.net community.
void OpenGLFrame::createShadowProjectionMatrix(float *l, float *e, float *n) {
   
   // These are c and d (corresponding to the tutorial)
   float d = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
   float c = e[0]*n[0] + e[1]*n[1] + e[2]*n[2] - d;
   
   // Create the matrix. OpenGL uses column by column
   // ordering
   shadowMatrix[0]  = l[0]*n[0]+c;
   shadowMatrix[4]  = n[1]*l[0];
   shadowMatrix[8]  = n[2]*l[0];
   shadowMatrix[12] = -l[0]*c-l[0]*d;
  
   shadowMatrix[1]  = n[0]*l[1];
   shadowMatrix[5]  = l[1]*n[1]+c;
   shadowMatrix[9]  = n[2]*l[1];
   shadowMatrix[13] = -l[1]*c-l[1]*d;
  
   shadowMatrix[2]  = n[0]*l[2];
   shadowMatrix[6]  = n[1]*l[2];
   shadowMatrix[10] = l[2]*n[2]+c;
   shadowMatrix[14] = -l[2]*c-l[2]*d;
  
   shadowMatrix[3]  = n[0];
   shadowMatrix[7]  = n[1];
   shadowMatrix[11] = n[2];
   shadowMatrix[15] = -d;
   
   // Finally multiply the matrices together *plonk*
   //~ glMultMatrixf(shadowMatrix);
}

/// It computes the correct world limits (used in the openglWorld definition)
/// It's computed in function of current currentmodel's BB 
/// It avoids distorsion on visualization
void OpenGLFrame::genWorldLimits() {
   
   if (currentmodel != 0) {
      mincoo[0] = currentmodel->mincoo[0]; mincoo[1] = currentmodel->mincoo[1]; mincoo[2] = currentmodel->mincoo[2];
      maxcoo[0] = currentmodel->maxcoo[0]; maxcoo[1] = currentmodel->maxcoo[1]; maxcoo[2] = currentmodel->maxcoo[2];
   }
   else {
      mincoo[0] = -1; mincoo[1] = -1; mincoo[2] = -1;
      maxcoo[0] =  1; maxcoo[1] =  1; maxcoo[2] =  1;
   }
   
   float xc = mincoo[0] + 0.5*(maxcoo[0]-mincoo[0]);
   float yc = mincoo[1] + 0.5*(maxcoo[1]-mincoo[1]);
   
   float WorldWidth  = abs(maxcoo[0]-mincoo[0]);
   float WorldHeight = abs(maxcoo[1]-mincoo[1]);
   
   if ((WorldHeight/WorldWidth) > ((float)height()/(float)width())) {
      WorldWidth = WorldHeight / ((float)height()/(float)width());
   }
   else if ((WorldHeight/WorldWidth) < ((float)height()/(float)width())) {
      WorldHeight = WorldWidth * ((float)height()/(float)width());
   }
   
   // world limits
   mincoo[0] = xc - 0.5*WorldWidth;
   mincoo[1] = yc - 0.5*WorldHeight;
   
   maxcoo[0] = xc + 0.5*WorldWidth;
   maxcoo[1] = yc + 0.5*WorldHeight;
   
   // center camera
   camcenter[0] = xc;
   camcenter[1] = yc;
   camcenter[2] = mincoo[2] + 0.5*(maxcoo[2]-mincoo[2]);
}

/// It sets the projection/modelview matrices
void OpenGLFrame::setGLview() {
   
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   
   WorldWidth  = abs(maxcoo[0]-mincoo[0])*0.5;
   WorldHeight = abs(maxcoo[1]-mincoo[1])*0.5;
   
   objDistance = 0.8660*(maxcoo[1]-mincoo[1]); /// sqrt(3)/2 = 0.8660
   //~ float objDistance = WorldHeight;
   nearplane = objDistance - objDistance*0.5;
   farplane  = nearplane + 20.0;
   
   cameye[0] = camcenter[0];
   cameye[1] = camcenter[1];
   cameye[2] = maxcoo[2] + objDistance;
   
   if (isProjOrtho) 
      glOrtho(-WorldWidth*zoomFactor,  WorldWidth*zoomFactor, 
              -WorldHeight*zoomFactor, WorldHeight*zoomFactor, 
               nearplane-2.0, farplane+2.0);
   else 
      gluPerspective(fovy*zoomFactor, (GLfloat)width()/(GLfloat)height(), nearplane, farplane);
   
   
   //~ glMatrixMode(GL_PROJECTION);
   //~ glLoadIdentity();
   //~ glOrtho(-0.15, 0.15, -0.15, 0.15, -2.0, 2.0);
   
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glViewport(0.0, 0.0, width(), height());
}
    
/// A simple resize callback.
/// @param width the width of the new window.
/// @param height the height of the new window.
void OpenGLFrame::resizeGL(int width, int height) {
   
    //~ int side = width < height ? width : height;
    //~ glMatrixMode (GL_PROJECTION);
    //~ glLoadIdentity ();
    //~ glOrtho (-1.0 * width/side, 1.0 * width/side, 
         //~ -1.0 * height/side, 1.0 * height/side, 10, -10);
    //~ glMatrixMode (GL_MODELVIEW);
    //~ glViewport(0, 0, width, height);
   
   checkingGLerrors("resizeGL()");
   
   setGLview();
   arcball.setBounds((GLfloat)width, (GLfloat)height);  //Update mouse bounds for the arcball
}

/// Callback for handling mouse button press.
/// @param event encapsulates the event's info.
void OpenGLFrame::mousePressEvent(QMouseEvent *event) {
   
   xini = event->x();
   yini = height()-event->y();
   list<unsigned int> sel_lista;
   // Do a different thing depending on interactionMode
   switch (interactionMode) {
      case SELECT_MODE: {
         // See which object was clicked
         if (!(event->modifiers() & Qt::ShiftModifier)) {
            selected.clear();
            group.clear();
         }
         
         // Left button rotates the object.
         if (event->button() == Qt::MidButton) {
            if (group.size() > 0) {
               // Create an arcball centered at the group.
            }
            else {
               // Create an arcball for the whole scene
               arcball.click(event->x(),height()-event->y());
               objectToScene = sceneTransform;
            }
            glDraw();
         }
         else if (event->button() == Qt::LeftButton) {
            grabStart = Point(event->x(), height() - event->y(), 0);
            //~ grabStart = screenToWorldOrtho(grabStart);
            
            /// Is the current keyball selected?
            cout<<"1ra opcion"<<endl;
            selection.begin(event->x(),height()-event->y());
            drawCurrentKeyPoint_Select();
            selection.end(sel_lista);
            
            if (not sel_lista.empty()) {
               was_ckeypointselected = true;
               objectToScene = keyPointCurrent->getTransformation();
               glDraw();
               break;
            }
            
            cout<<"2da opcion"<<endl;
            /// Is the shadow current keyball selected?
            selection.begin(event->x(),height()-event->y());
            drawShadowCurrentKeyPoint_Select();
            selection.end(sel_lista);
            
            if (not sel_lista.empty()) {
               is_shadowdragging = true;
               was_ckeypointselected = true;
               
               objectToScene = keyPointCurrent->getTransformation();
               grabStart = getPointOverFloor(Point(event->x(), height() - event->y(), 0));
               
               glDraw();
               break;
            }
            
            /// Is some keyball selected?
            cout<<"3ra opcion"<<endl;
            selection.begin(event->x(),height()-event->y());
            drawKeyPoints_Select();
            selection.end(sel_lista);
            
            if (not sel_lista.empty()) {
               currentKey = sel_lista.front();
               keyPointCurrent->setTransformation(keyPoints[currentKey]->getTransformation());
               retrieveStance(currentKey);
               if (deformer != 0) {
                  for (unsigned int i = 0; i < objects.size(); i++) {
                     const Point &p = objects[i]->box.center();
                     constraints.setPosition(i, Point3(p[0],p[1],p[2]));
                  }
                  deformer->execute_deformation(&constraints);
               }
               glDraw();
               break;
            }
            
            
            cout<<"4ta opcion"<<endl;
            selection.begin(event->x(),height()-event->y());
            drawObjectsConstraints_Select();
            selection.end(sel_lista);
            
            cout<<"... sel_lista: "<<sel_lista.size()<<endl;
            
            // Include the object being altered
            if (not sel_lista.empty()) {
               int isel = sel_lista.front();
               //~ std::copy(sel_lista.begin(), sel_lista.end(), ostream_iterator<unsigned int>(cout, " "));
               
               int idkp = 1 + objects.size(); // index of "current" key point
               if (isel == idkp) { 
                  cout<<" ... isel: "<<isel<<endl;
                  //~ if (group.add(keyPointCurrent)) selected.push_back(isel);
                  group.clear();
                  selected.clear();
                  group.add(keyPointCurrent);
               }
               else if (isel < (int) objects.size()) {
                  cout<<" ... isel ..: "<<isel<<endl;
                  // add only if not already there
                  if (group.add(objects[isel])) { cout<<"xxx"<<endl; selected.push_back(isel); cout<<"yyy"<<endl; }
               }
               else {
                  cout<<" ... isel ... : "<<isel<<endl;
                  //~ storeStance();
                  currentKey = isel-objects.size();
                  
                  group.clear();
                  selected.clear();
                  group.add(keyPoints[currentKey]);
               }
               if (group.size()>0) {
                  objectToScene = group.getTransformation();
               }
               glDraw();
               break;
            }
            
            cout<<"5ta opcion"<<endl;
            /// Is the shadow current keyball selected?
            selection.begin(event->x(),height()-event->y());
            drawShadowObjectsConstraints_Select();
            selection.end(sel_lista);
            //~ cout<<"sel_lista.size(): "<<sel_lista.size()<<endl;
            
            // Include the object being altered
            if (not sel_lista.empty()) {
               int isel = sel_lista.front();
               //~ std::copy(sel_lista.begin(), sel_lista.end(), ostream_iterator<unsigned int>(cout, " "));
               
               int idkp = 1 + objects.size(); // index of "current" key point
               if (isel == idkp) {
                  //~ if (group.add(keyPointCurrent)) selected.push_back(isel);
                  group.clear();
                  selected.clear();
                  group.add(keyPointCurrent);
               }
               else if (isel < (int) objects.size()) {
                  // add only if not already there
                  if (group.add(objects[isel])) { selected.push_back(isel); }
               }
               else {
                  //~ storeStance();
                  currentKey = isel-objects.size();
                  
                  group.clear();
                  selected.clear();
                  group.add(keyPoints[currentKey]);
               }
               if (group.size()>0) {
                  objectToScene = group.getTransformation();
                  is_shadowdragging = true;
                  grabStart = getPointOverFloor(Point(event->x(), height() - event->y(), 0));
               }
               glDraw();
               break;
            }
         }
         else if (event->button() == Qt::RightButton) {
            // Right button translates
            grabStart = Point(event->x(), height() - event->y(), 0);
            //~ grabStart = screenToWorldOrtho(grabStart);
            if (group.size()>0) {
               objectToScene = group.getTransformation();
            }
            else {
               objectToScene = sceneTransform;
            }
            glDraw();
         }
         break; // End of case SELECT_MODE
      }
      case RESTRICTION_MODE: {
         grabStart = Point(event->x(), height() - event->y(), 0);
         //~ grabStart = screenToWorldOrtho(grabStart);
         // Restriction placement mode
         if (event->button() == Qt::LeftButton) {
            
            selection.begin(event->x(),height()-event->y());
            drawObjectsConstraints_Select();
            selection.end(sel_lista);
            
            if (not sel_lista.empty()) { glDraw(); break; }
            
            /// If is there an skeleton to use its joints for setting control points
            /// otherwise use the vertices of the mesh
            selection.begin(event->x(),height()-event->y());
            if (currentmodel->skeleton == 0)
               GLdrawVerticesForSelection(currentmodel);
            else
               GLdrawVerticesForSelection(currentmodel->skeleton);
            selection.end(sel_lista);
            
            if (not sel_lista.empty()) {
               int isel = sel_lista.front();
               cout<<"v selecionado: "<<isel<<endl;
               Point3 p;
               if (currentmodel->skeleton == 0)
                  p = currentmodel->getVertexPosition(isel);
               else
                  p = currentmodel->skeleton->getJointPosition(isel);
               
               cursor3D = Point (p[0], p[1], p[2]);
               addRestriction();
               
               Point3 po(p[0], p[1], p[2]);
               constraints.push_back(po, isel);
            }
            glDraw();
         }
         else if (event->button() == Qt::RightButton) {
            // Right button translates
            grabStart = Point(event->x(), height() - event->y(), 0);
            //~ grabStart = screenToWorldOrtho(grabStart);
            if (group.size()>0) {
               objectToScene = group.getTransformation();
            }
            else {
               objectToScene = sceneTransform;
            }
            glDraw();
         }
         // Left button rotates the scene.
         else if (event->button() == Qt::MidButton) {
            if (group.size() > 0) {
               // Create an arcball centered at the group.
            }
            else {
               // Create an arcball for the whole scene
               arcball.click(event->x(),height()-event->y());
               objectToScene = sceneTransform;
            }
            glDraw();
         }
         break;
      }
      case ANIMATE_MODE: {
         if (event->button() == Qt::LeftButton) {
            grabStart = Point(event->x(), height() - event->y(), 0);
            
            cout<<" ANIMATE_MODE !!!!! event->button() == Qt::LeftButton"<<endl;
            
            /// Test if there are some keypoints
            if (keyPoints.size() < 2) {
               cout<<" ... #t here are not sufficient keyposes!"<<endl;
               glDraw();
               break;
            }
            
            cout<<"111"<<endl;
            
            /// Test if one keyball was selected
            selection.begin(event->x(),height()-event->y());
            drawKeyPoints_Select();
            selection.end(sel_lista);
            if (not sel_lista.empty()) {
               currentKey = sel_lista.front();
               keyPointCurrent->setTransformation(keyPoints[currentKey]->getTransformation());
               cout<<"if if if"<<endl;
               //~ glDraw();
               //~ break;
            }
            
            cout<<"222"<<endl;
            
            /// Test if the current keyball was selected
            sel_lista.clear();
            selection.begin(event->x(),height()-event->y());
            drawCurrentKeyPoint_Select();
            selection.end(sel_lista);
            
            if (sel_lista.empty()) {
               cout<<"if if if"<<endl;
               // Test if the shadow of the current keyball was selected
               selection.begin(event->x(),height()-event->y());
               drawShadowCurrentKeyPoint_Select();
               selection.end(sel_lista);
               
               if (not sel_lista.empty()) {
                  cout<<"if if if not"<<endl;
                  is_shadowdragging = true;
                  grabStart = getPointOverFloor(Point(event->x(), height() - event->y(), 0));
               }
            }
            
            cout<<"333"<<endl;
            
            /// See if the current keyball or its shadow will be altered
            if (not sel_lista.empty()) {
               cout<<"if if if"<<endl;
               was_ckeypointselected = true;
               objectToScene = keyPointCurrent->getTransformation();
               
               buildFrameSet();
               poseInterpolator = new RbfPoseInterpolator(frameSet);
               
               /*
               if (deformer==0) {
                  //~ deformer = new DeformationMesh(currentmodel);
                  deformer = new DeformationSkelMesh(currentmodel);
                  //~ deformer = new DeformationMesh_VSGPU;
                  //~ deformer = new DeformationMesh_FSGPU;
                  //~ deformer = new DeformationMesh_FSGPU_L1;
                  deformer->setting(&constraints);
               }
               */
               //~ else {
                  // Update the mesh with the current skeleton pose
                  Point po = keyPointCurrent->box.center();
                  retrievePose(po);
                  for (unsigned int i = 0; i < objects.size(); i++) {
                     const Point &p = objects[i]->box.center();
                     constraints.setPosition(i, Point3(p[0],p[1],p[2]));
                  }
                  deformer->execute_deformation(&constraints);
               //~ }
               // clear animation data 
               poses.clear();
            }
            glDraw();
         }
         // Left button rotates the object.
         if (event->button() == Qt::MidButton) {
            if (group.size() > 0) {
               // Create an arcball centered at the group.
            }
            else {
               // Create an arcball for the whole scene
               arcball.click(event->x(),height()-event->y());
               objectToScene = sceneTransform;
            }
            glDraw();
         }
         else if (event->button() == Qt::RightButton) {
            // Right button translates
            grabStart = Point (event->x(), height() - event->y(), 0);
            if (group.size()>0) {
               objectToScene = group.getTransformation();
            }
            else {
               objectToScene = sceneTransform;
            }
            glDraw();
         }
      }
   }
}

/// Callback for handling mouse movements.
/// @param event encapsulates the event's info.
void OpenGLFrame::mouseMoveEvent(QMouseEvent *event) {
   
   cout<<"mouseMoveEvent ..."<<endl;
   
   //~ switch (interactionMode) {
      //~ case SELECT_MODE: {
         // Drag with left button rotates the object.
         if ((event->buttons() & Qt::MidButton)) {
            
            // Pass the mouse movement to the arcball.
            /// arcball->mouseDrag(event->x(),height()-event->y());
            arcball.drag(event->x(),height()-event->y(),tM);
            Transformation mTransf(tM[0], tM[4], tM[8],  tM[12],
                                   tM[1], tM[5], tM[9],  tM[13],
                                   tM[2], tM[6], tM[10], tM[14]);
            
            // Compose transformation with that of the arcball.
            if (group.size()>0) {
               group.setTransformation (
               sceneToObject*mTransf*objectToScene);
            } else {
               sceneTransform = mTransf*objectToScene;
            }
            glDraw();
         }
         else if (event->buttons() & Qt::RightButton) {
            //~ cout<<"event->buttons() & Qt::RightButton"<<endl;
            // Translation
            
            //~ Point s = screenToWorldOrtho(grabStart);
            //~ Point grabEnd(event->x(), height() - event->y(), 0);
            //~ grabEnd = screenToWorldOrtho(grabEnd);
            //~ Vector worldDisplacement = grabEnd-s;
            
            Point grabEnd(event->x(), height() - event->y(), 0);
            Vector wd = getWorldDisplacement(grabStart, grabEnd);
            sceneTransform = objectToScene*Transformation(CGAL::TRANSLATION, wd);
            
            glDraw();
         }
         else if ((event->buttons() & Qt::LeftButton) && poseInterpolator) {
            cout<<"-> (event->buttons() & Qt::LeftButton) && poseInterpolator"<<endl;
            Vector wd(0,0,0);
            if (is_shadowdragging) {
               //~ cout<<"is_shadowdragging true "<<endl;
               Point grabEnd = getPointOverFloor(Point(event->x(), height() - event->y(), 0));
               wd = grabEnd-grabStart;
            }
            else {
               //~ cout<<"is_shadowdragging false "<<endl;
               Point grabEnd(event->x(), height() - event->y(), 0);
               wd = getWorldDisplacement(grabStart, grabEnd);
            }
            //~ Point grabEnd(event->x(), height() - event->y(), 0);
            //~ Vector wd = getWorldDisplacement(grabStart, grabEnd);
            
            keyPointCurrent->setTransformation(Transformation(CGAL::TRANSLATION, wd)*objectToScene);
            Point po = keyPointCurrent->box.center();
            retrievePose(po);
            
            //~ interKeyPoints.push_back(po);
            
            std::vector<Vector> pose;
            pose.reserve(constraints.size());
            // Update the deformed positions of control points and compute the deformation
            for (unsigned int i = 0; i < objects.size(); i++) {
               const Point &p = objects[i]->box.center();
               
               Point3 plast = constraints.getPosition(i);
               constraints.setPosition(i, Point3(p[0],p[1],p[2]));
               
               Vector t(p[0]-plast[0],p[1]-plast[1],p[2]-plast[2]);
               pose.push_back(t);
               //~ cout<<"-->t: "<<t<<endl;
            }
            cout<<"sssssssssssssssssssss"<<endl;
            deformer->execute_deformation(&constraints);
            poses.push_back(pose); // save the poses for animation purposes
            cout<<"sssssssssssssssssssss xxxxxxxxxxxxxxxxxx"<<endl;
            glDraw();
         }
         else if (event->buttons() & Qt::LeftButton) {
            //~ cout<<"-->(event->buttons() & Qt::LeftButton) "<<endl;
            Vector wd(0,0,0);
            if (is_shadowdragging) {
               cout<<"is_shadowdragging true "<<endl;
               Point grabEnd = getPointOverFloor(Point(event->x(), height() - event->y(), 0));
               wd = grabEnd-grabStart;
            }
            else {
               //~ cout<<"is_shadowdragging false "<<endl;
               Point grabEnd(event->x(), height() - event->y(), 0);
               wd = getWorldDisplacement(grabStart, grabEnd);
            }
            
            //~ cout<<"--> wd: "<<wd<<endl;
            if (was_ckeypointselected) {
               cout<<"was_ckeypointselected true "<<endl;
               //~ keyPointCurrent->setTransformation(Transformation(CGAL::TRANSLATION, t) * objectToScene);
               keyPointCurrent->setTransformation(
               Transformation(CGAL::TRANSLATION, wd) * objectToScene);
            }
            else if (group.size()>0) { 
               //~ cout<<"was_ckeypointselected false "<<endl;
               group.setTransformation (
               Transformation(CGAL::TRANSLATION, wd) * objectToScene);
               
               if (deformer != 0) {
                  //~ cout<<"if deformer != 0 deformer != 0 deformer != 0"<<endl;
                  assert(constraints.size() == objects.size());
                  // Update the deformed positions of control points and compute the deformation
                  unsigned int isel=0;
                  for (unsigned int i = 0; i < objects.size(); i++) {
                     //~ cout<<"i::: "<<i<<endl;
                     Transformation T;
                     if (isel < selected.size() && selected [isel] == (int) i) {
                        // this is a selected object
                        isel++;
                        T = objects[i]->getTransformation()*group.getTransformation();
                     }
                     else {
                        T = objects[i]->getTransformation();
                     }
                     
                     float x=T.m(0,3);
                     float y=T.m(1,3);
                     float z=T.m(2,3);
                     constraints.setPosition(i, Point3(x,y,z));
                  }
                  //~ cout<<"i::: ::: before"<<endl;
                  deformer->execute_deformation(&constraints);
                  //~ cout<<"i::: ::: after"<<endl;
               }
               else {
                  //~ cout<<"else deformer != 0 deformer != 0 deformer != 0"<<endl;
               }
            }
            glDraw();
         }
         //~ break;
      //~ }
      //~ case ANIMATE_MODE: {
         //~ break;
      //~ }
      //~ default: {}
   //~ }
}

/// Callback for handling mouse button release.
/// @param event encapsulates the event's info.
void OpenGLFrame::mouseReleaseEvent(QMouseEvent *event) {
   
   //~ switch (interactionMode) {
      //~ case SELECT_MODE: {
         //~ if (group.size() > 0) {
            //~ group.propagateTransformation();
         //~ }
         //~ break;
      //~ }
      //~ case ANIMATE_MODE: {
         //~ if (event->button() == Qt::LeftButton && poseInterpolator) {
            //~ delete poseInterpolator;
            //~ poseInterpolator = 0;
            
            //~ if (not was_ckeypointselected) {
               //~ retrieveStance(currentKey);
            //~ }
            //~ glDraw();
         //~ }
         //~ break;
      //~ }
   //~ }
   //~ was_ckeypointselected = false;
   
   cout<<"mouseReleaseEvent ... "<<endl;
   
   //~ switch (interactionMode) {
      //~ case SELECT_MODE: {
         if (group.size() > 0) {
            //~ cout<<"11111111"<<endl;
            group.propagateTransformation();
         }
         //~ break;
      //~ }
      //~ case ANIMATE_MODE: {
         if (event->button() == Qt::LeftButton && poseInterpolator) {
            //~ cout<<"22222222222"<<endl;
            delete poseInterpolator;
            poseInterpolator = 0;
            
            if (not was_ckeypointselected) {
               retrieveStance(currentKey);
            }
            glDraw();
         }
         switch (interactionMode) {
            case SELECT_MODE: {
               if (event->button() == Qt::LeftButton) {
                  if (not (event->modifiers() & Qt::ShiftModifier)) return;
                  
                  int x = event->x();
                  int y = height()-event->y();
                  list<int> sel_lista;
                  
                  selection.begin(int(xini+0.5*(x-xini)), int(yini+0.5*(y-yini)), abs(x-xini), abs(y-yini));
                  drawObjectsConstraints_Select();
                  selection.endAll(sel_lista);
                  
                  //~ cout<<"sel_lista.size(): "<<sel_lista.size()<<endl;
                  std::copy(sel_lista.begin(),sel_lista.end(), ostream_iterator<unsigned int>(cout," "));
                  //~ std::copy(sel_lista.begin(),sel_lista.end(), selected.begin());
                  
                  selected.clear();
                  group.clear();
                  list<int>::iterator it = sel_lista.begin();
                  while (it != sel_lista.end()) {
                     //~ selected.push_back();
                     int id = *it++;
                     if (group.add(objects[id])) { selected.push_back(id); }
                  }
                  
               }
            }
            glDraw();
         }
         //~ break;
      //~ }
   //~ }
   was_ckeypointselected = false;
   is_shadowdragging = false;
   
   cout<<" ... mouseReleaseEvent ... done"<<endl;
}

void OpenGLFrame::keyPressEvent(QKeyEvent *event) {
   
   cout<<" ... keyPressEvent() ..."<<endl;
   if (event->key() == Qt::Key_Escape) {
      exit(0);
   }
   else if (event->key() == Qt::Key_A) {
      constraints.translate(0, Vector3(0.3,0.4,0.0));
      deformer->execute_deformation(&constraints);
   }
   else if (event->key() == Qt::Key_T) {
      objects[0]->setTransformation(objects[0]->getTransformation()*
         Transformation(CGAL::TRANSLATION, Vector(-0.3,0.2,0.0)));
      objects[1]->setTransformation(objects[1]->getTransformation()*
         Transformation(CGAL::TRANSLATION, Vector( 0.3,0.2,0.0)));
      constraints.translate(0, Vector3(-0.3,0.2,0.0));
      constraints.translate(1, Vector3( 0.3,0.2,0.0));
      deformer->execute_deformation(&constraints);
   }
   glDraw();
}

/// Implements the "cut" operation. Copies selected objects to the cutbuffer and removes them.
void OpenGLFrame::cut () 
{
    this->copy();
    sort(selected.begin(), selected.end());
    for (std::vector<int>::reverse_iterator p = selected.rbegin(); p != selected.rend(); p++) {
      int k = *p;
      assert (k < (int) objects.size() && k >= 0);
      // If this is the deformable mesh, then undefine it
      if (objects[k] == deformableMesh) {
          deformableMesh = 0;
      }
      // Deallocate the object
      delete objects[k];
      // Shift remaining items 
      for (unsigned i = (unsigned) k; i < objects.size()-1; i++) {
          objects[i] = objects[i+1];
      }
      // Shrink array
      objects.pop_back();
    }
    selected.clear();
    glDraw();
}

/// Implements the "paste" operation. Appends objects from the cutbuffer to the objects array.
void OpenGLFrame::paste ()
{
   for (unsigned i = 0; i < cutBuffer.size(); i++) {
      objects.push_back(new DrawableInstance (*cutBuffer[i]));
   }
   glDraw();
}


/// Implements the "copy" operation. Copies selected objects to the cutbuffer.
void OpenGLFrame::copy ()
{
   // First deallocate all objects in the cutbuffer
   for (unsigned i = 0; i < cutBuffer.size(); i++) {
      // If this is the deformable mesh, then undefine it
      if (cutBuffer[i] == deformableMesh) {
         deformableMesh = 0;
      }
      delete cutBuffer[i];
   }
   cutBuffer.clear();
   
   // Copy selected objects to cutBuffer
   for (unsigned i = 0; i < selected.size(); i++) { 
      cutBuffer.push_back(new DrawableInstance(*objects[selected[i]]));
   }
   glDraw();
}

/// Inplements zoom operations using the mouse wheel
void OpenGLFrame::wheelEvent(QWheelEvent *e) {
   
   //~ if (e->delta()>0) zoomFactor+= 0.1;
   //~ else              zoomFactor-= 0.1;
   //~ e->accept(); 
   //~ setGLview();
   //~ glDraw();
   
   if (e->delta()>0) zoomIn();
   else              zoomOut();
      
   e->accept(); 
}

/// Implements the "zoomin" operation. Narrows the view of the scene.
void OpenGLFrame::zoomIn ()
{
   sceneTransform = Transformation (CGAL::SCALING, 1.2) * sceneTransform;
   glDraw();
}

/// Implements the "zoomout" operation. Enlarges the view of the scene.
void OpenGLFrame::zoomOut ()
{
   sceneTransform = Transformation (CGAL::SCALING, 1.0/1.2) * sceneTransform;
   glDraw();
}

/// Implements the "zoomAll" operation
/// Computes a scene viewing transformation so that all objects are shown.
void OpenGLFrame::zoomAll ()
{
   if (objects.size() == 0) {
      // A simple identity transformation suffices for exhibiting 0 objects
      sceneTransform = Transformation(CGAL::IDENTITY);
   } else {
      Bbox allbox (objects[0]->box);
      for (unsigned i = 0; i < objects.size(); i++) {
         allbox = allbox + objects[i]->box;
      }
      double d = allbox.diameter();
      if (d == 0) d = 1.0;
      Point c = allbox.center();
      sceneTransform = Transformation(CGAL::SCALING, 2.0/d) 
                  * Transformation(CGAL::TRANSLATION, Point(0,0,0)-c)
                  * rotationComponent(sceneTransform);
   }
   glDraw();
}

Vector OpenGLFrame::getWorldDisplacement(const Point &s, const Point &e) {
   
   glGetIntegerv(GL_VIEWPORT, viewport);
   glGetDoublev(GL_MODELVIEW_MATRIX, mMtx);
   
   /// Compute the world coordinates using the orthographic projection
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   glLoadIdentity();
   glOrtho(-WorldWidth*zoomFactor,  WorldWidth*zoomFactor, 
           -WorldHeight*zoomFactor, WorldHeight*zoomFactor, 
            nearplane, farplane);
   glGetDoublev(GL_PROJECTION_MATRIX, pMtx);
   glPopMatrix();
   
   GLdouble ws[3], we[3];
   gluUnProject(s[0], s[1], s[2], mMtx, pMtx, viewport, &ws[0], &ws[1], &ws[2]);
   gluUnProject(e[0], e[1], e[2], mMtx, pMtx, viewport, &we[0], &we[1], &we[2]);
   
   return Vector(we[0]-ws[0], we[1]-ws[1], we[2]-ws[2]);
}

Point OpenGLFrame::screenToWorldOrtho (Point p) {
   
   double wldcoord[3];
   glGetIntegerv (GL_VIEWPORT, viewport);
   glGetDoublev (GL_MODELVIEW_MATRIX, mMtx);
   
   /// Compute the world coordinates using the orthographic projection
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   glLoadIdentity();
   glOrtho(-WorldWidth*zoomFactor,  WorldWidth*zoomFactor, 
           -WorldHeight*zoomFactor, WorldHeight*zoomFactor, 
            nearplane, farplane);
   glGetDoublev (GL_PROJECTION_MATRIX, pMtx);
   glPopMatrix();
   
   gluUnProject (p.x(), p.y(), p.z(),mMtx, pMtx, viewport,
                 &wldcoord[0], &wldcoord[1], &wldcoord[2]);
   return Point (wldcoord[0], wldcoord[1], wldcoord[2]);
}

Point OpenGLFrame::getPointOverFloor(Point p) {
   
   double wldcoord[3];
   glGetIntegerv(GL_VIEWPORT, viewport);
   glGetDoublev(GL_MODELVIEW_MATRIX, mMtx);
   glGetDoublev(GL_PROJECTION_MATRIX, pMtx);
   
   // Project the point over the front plane
   gluUnProject(p.x(), p.y(), 0.0, mMtx, pMtx, viewport,
                 &wldcoord[0], &wldcoord[1], &wldcoord[2]);
   Point a(wldcoord[0], wldcoord[1], wldcoord[2]);
   
   // Project the point over the back plane
   gluUnProject(p.x(), p.y(), 1.0, mMtx, pMtx, viewport,
                 &wldcoord[0], &wldcoord[1], &wldcoord[2]);
   Point b(wldcoord[0], wldcoord[1], wldcoord[2]);
   Segment seg(a,b);
   
   // Compute the intersection point between the segment ab and the floor
   CGAL::Object result;
   Point ipoint;
   Segment iseg;
   
   result = CGAL::intersection(pfloor, seg);
   if (CGAL::assign(ipoint, result)) {
      // handle the point intersection case.
      return ipoint;
   } else
         if (CGAL::assign(iseg, result)) {
            // handle the segment intersection case.
            return a;
         } else {
            // handle the no intersection case.
            return a;
         }
   
   return a;
}

/// Groups the selected objects
void OpenGLFrame::makeGroup ()
{
}

/// Ungroups the selected objects
void OpenGLFrame::breakGroup ()
{
}

/// Stores the current pose into keyStances
void OpenGLFrame::storeStance (int keyNumber)
{
   DrawableInstance* key = keyPoints [keyNumber];
   keyStances[key] = StanceMap();
   StanceMap& pm = keyStances[key];
    for (unsigned int i = 0; i < objects.size(); i++) {
      Transformation t;
      t = objects[i]->getTransformation();
      pm [objects[i]] = t;
   }
}

/// Retrieves the object transformations from keyStances
/// @param keyNumber index for the desired pose in keyPoints
void OpenGLFrame::retrieveStance (int keyNumber)
{
   assert (keyNumber >= 0 && keyNumber< (int) keyPoints.size());
   DrawableInstance* key = keyPoints [keyNumber];
   StanceMap& pm = keyStances[key];
   for (unsigned int i = 0; i < objects.size(); i++) {
      StanceMap::iterator j = pm.find(objects[i]);
      if (j != pm.end()) {
         Transformation t = j->second;
         objects[i]->setTransformation(t);
      }
   }
}

/// Retrieves the object transformations from the pose interpolator
/// @param keyNumber index for the desired pose in keyPoints
void OpenGLFrame::retrievePose (const Point& point) 
{
   Pose pose;
   assert(poseInterpolator);
   poseInterpolator->interpolatePose(point, pose);
   assert (pose.size() == objects.size());
   for (unsigned int i = 0; i < objects.size(); i++) {
      objects[i]->setTransformation(pose[i]);
   }
}

/// Builds frameSet from keyPoses
void OpenGLFrame::buildFrameSet ()
{
   cout<<"buildFrameSet(): "<<endl;
   cout<<"keyPoints.size(): "<<keyPoints.size()<<endl;
   cout<<"objects.size(): "<<objects.size()<<endl;
   
   /// Start with an empty frameset
   frameSet.clear();
   
   /// build a frame for each stance associated to each keypoint
   for (unsigned int keynum = 0; keynum < keyPoints.size(); keynum++) {
      DrawableInstance* key = keyPoints[keynum];
      Frame f;
      f.keyPoint = key->box.center();
      StanceMap& pm = keyStances[key];
      for (unsigned int i = 0; i < objects.size(); i++) {
         StanceMap::iterator j = pm.find(objects[i]);
         Transformation t = (j != pm.end()) ? j->second : Transformation (CGAL::IDENTITY);
         f.pose.push_back (t);
      }
      frameSet.push_back (f);
   }
   
   cout<<"buildFrameSet(): end "<<endl;
}

void OpenGLFrame::loadKeyPointSpriteTexture() {
   
   glActiveTexture(GL_TEXTURE0);
   spriteKeyPoints = new Texture("icons/redballTKey.png", GL_TEXTURE_2D);
   assert(spriteKeyPoints != 0);
}

void OpenGLFrame::animate(int animindex) {
   
   const Point &p = interKeyPoints[animindex];
   retrievePose(p);
   
   for (unsigned int i = 0; i<objects.size(); i++) {
      const Point &p = objects[i]->box.center();
      constraints.setPosition(i, Point3(p[0],p[1],p[2]));
   }
   deformer->execute_deformation(&constraints);
   
   glDraw();
}

void OpenGLFrame::animate_poses(int index_pose) {
   
   if (index_pose < 0) return;
   
   assert(constraints.size() == objects.size());
   if (index_pose == 0) {
      currentKey = 0;
      keyPointCurrent->setTransformation(keyPoints[currentKey]->getTransformation());
      retrieveStance(currentKey);
      
      for (unsigned int i = 0; i<constraints.size(); ++i) {
         const Point &p = objects[i]->box.center();
         constraints.setPosition(i, Point3(p[0],p[1],p[2]));
      }
      deformer->execute_deformation(&constraints);
      //~ poseid = index_pose;
      
      i_constraints = constraints;
      
      const vector<Vector> &pose = poses[0];
      for (unsigned int i = 0; i<constraints.size(); ++i) {
         const Vector &t = pose[i];
         constraints.translate(i, Vector3(t[0],t[1],t[2]));
      }
      deformer->execute_deformation(&constraints);
      poseid = 0;
   }
   else if (index_pose > poseid) {
      do {
         ++poseid;
         const vector<Vector> &pose = poses[poseid];
         for (unsigned int i = 0; i<constraints.size(); ++i) {
            const Vector &t = pose[i];
            constraints.translate(i, Vector3(t[0],t[1],t[2]));
         }
         deformer->execute_deformation(&constraints);
      } while (poseid < index_pose);
   }
   else if (index_pose < poseid) {
      do {
         --poseid;
         const vector<Vector> &pose = poses[poseid];
         for (unsigned int i = 0; i<constraints.size(); ++i) {
            const Vector &t = pose[i];
            constraints.translate(i, Vector3(-t[0],-t[1],-t[2])); // in reverse
         }
         deformer->execute_deformation(&constraints);
      } while (poseid > index_pose);
   }
   
   glDraw();
}

void OpenGLFrame::play() {
   
   buildFrameSet();
   poseInterpolator = new RbfPoseInterpolator (frameSet);
   
   //~ connect(&timer, SIGNAL(timeout()), SLOT(animate()));
   //~ timer.start(0);
}

//~ void OpenGLFrame::stop() {
   
   //~ animindex = 0;
   //~ disconnect(&timer, 0, 0, 0);
   //~ timer.start(100000);
//~ }

//~ void OpenGLFrame::pause() {
   
   //~ disconnect(&timer, 0, 0, 0);
//~ }

void OpenGLFrame::record() {
   
   if (is_pic_capturing) {
      //~ cout<<"record(): is_pic_capturing true"<<endl;
      QPixmap qp = renderPixmap();
      QString fileName;
      if (id_picgrab<10)        fileName = QString("./output/pic0000%1.png").arg(id_picgrab);
      else if (id_picgrab<100)  fileName = QString("./output/pic000%1.png").arg(id_picgrab);
      else if (id_picgrab<1000) fileName = QString("./output/pic00%1.png").arg(id_picgrab);
      else                      fileName = QString("./output/pic0%1.png").arg(id_picgrab);
         
      bool ok = qp.save(fileName,"PNG");
   }
   if (is_mesh_capturing) {
      //~ cout<<"record(): is_mesh_capturing true"<<endl;
      QString fileName = QString("./output/mesh%1.off").arg(id_picgrab);
      currentmodel->saveShapeOFF(fileName.toStdString().c_str());
   }
   ++id_picgrab;
   
   //~ animindex=0;
   //~ interKeyPoints.clear();
   
   //~ if (deformer==0) deformer = new DeformationSkelShape;
   //~ deformer = new DeformationShape;
   //~ deformer->setting(currentmodel, &constraints);
}

void OpenGLFrame::resetAll() {
   
   // recover the initial model data
   currentmodel->recoverInitData();
   
   // clear the animation data
   cout<<"resetAll aaaa"<<endl;
   objects.clear();
   keyPoints.clear();
   constraints.clear();
   i_constraints.clear();
   
   poses.clear();
   trans.clear();
   
   if (deformer != 0) { delete deformer; deformer = 0; }
   cout<<"resetAll bbbb"<<endl;
   glDraw();
   
}

void OpenGLFrame::executeDeformation() {
   
   if (deformer == 0) return;
   deformer->execute_deformation(&constraints);
}

void OpenGLFrame::setRotationCompTech(RotationCompTech r) {
   
   rotationCompTech = r;
   if (deformer == 0) return;
   deformer->setRotationCompTech(rotationCompTech);
}
